package com.sc.nft.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sc.nft.config.hna.HnaConfig;
import com.sc.nft.config.sand.SandConfig;
import com.sc.nft.config.sand.SandPayUtil;
import com.sc.nft.dao.*;
import com.sc.nft.dto.HnaRefundDto;
import com.sc.nft.dto.WantBuyDTO;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.SaasTaskBurialPointDTO;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.helper.LlPayHelper;
import com.sc.nft.helper.MessageQueueHelper;
import com.sc.nft.service.*;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.util.OrderNoUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.math.BigDecimal;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 卷轴商店求购表服务接口实现
 *
 * @author zxy
 * @since 2024-09-04 02:15:00
 * @description 由 Mybatisplus Code Generator 创建
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class ScrollWantBuyServiceImpl implements ScrollWantBuyService {
    private final ScrollWantBuyDao scrollWantBuyDao;
    private final PayOrderDao payOrderDao;
    private final LlPayHelper llPayHelper;
    private final HnaConfig hnaConfig;
    private final UserHnaExtService userHnaExtService;
    private final UserWalletService userWalletService;
    private final ScrollShopDao scrollShopDao;
    private final StaticDataDao staticDataDao;
    private final UserEquityPropsDao userEquityPropsDao;
    private final UserRelevanceDao userRelevanceDao;
    private final ScrollConfigDao scrollConfigDao;
    private final UserEquityPropsService userEquityPropsService;
    private final EquityPropsDao equityPropsDao;
    private final MessageQueueHelper messageQueueHelper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeWantBuyOrder(Long id, UserInfo userInfo,String dealPassword) {
        ScrollWantBuy wantBuy = scrollWantBuyDao.getById(id);
        Assert.notNull(wantBuy,()->new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(wantBuy.getShopUserId().longValue()==userInfo.getId().longValue(),()->new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        switch (wantBuy.getStatus()) {
            case WAIT_PAY:
                wantBuy.setStatus(WantBuyOrderStatusEnum.CLOSE);
                wantBuy.updateById();
                break;
            case IN_BUY:
                if(!StrUtil.equals(userInfo.getTransactionPassword(),dealPassword)){
                    throw new GlobalRunTimeException(ErrorCode.PAYMENT_PASSWORD_WAS_ENTERED_INCORRECTLY);
                }
                PayOrder payOrder = payOrderDao.getByOrderNo(wantBuy.getOrderNo());
                if(ObjectUtil.isNull(payOrder)||payOrder.getOrderType()!= PayTypeEnum.SCROLL_BUY||payOrder.getStatus()!= PayStatusEnum.SUCCESS){
                    throw new GlobalRunTimeException("原订单支付未成功");
                }
                payOrder.setRefundAmount(wantBuy.getSurplusPrice());
                payOrder.setRefundTradeNo(UUID.fastUUID().toString(true));
                payOrder.updateById();
                switch (payOrder.getChannel()) {
                    case SAND:
                        MallPayOrderRecord mallPayOrderRecord = new MallPayOrderRecord();
                        mallPayOrderRecord.setTradeNo(payOrder.getRefundTradeNo());
                        mallPayOrderRecord.setRefundAmount(payOrder.getRefundAmount());
                        mallPayOrderRecord.setNotifyUrl(SandConfig.MALL_REFUND_NOTIFY_URL);
                        JSONObject jsonObject = SandPayUtil.refundRequest(mallPayOrderRecord, payOrder.getTradeNo(), "退款");
                        JSONObject head= (JSONObject) jsonObject.get("head");
                        String  respCode=(String)head.get("respCode");
                        if (!respCode.equals("000000")) {
                            throw new GlobalRunTimeException("杉德退款失败:"+head.get("respMsg"));
                        }
                        break;
                    case LL_PAY:
                        llPayHelper.refund(userInfo,payOrder.getTradeNo(),payOrder.getRefundTradeNo(),payOrder.getRefundAmount().setScale(2, BigDecimal.ROUND_DOWN).toPlainString(),"",payOrder);
                        break;
                    case HNA_PAY:
                        HnaRefundDto dto = new HnaRefundDto();
                        dto.setOrderAmount(payOrder.getPayAmount().toPlainString());
                        dto.setRefundAmount(payOrder.getRefundAmount().toPlainString());
                        dto.setRefundType("1");
                        dto.setRemark("手动退款");
                        dto.setOrgSubmitTime(DateUtil.format(payOrder.getCreateTime(),
                                DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
                        dto.setOrgMerOrderId(payOrder.getTradeNo());
                        dto.setNotifyUrl(hnaConfig.getT005NonMallNotifyUrl());
                        userHnaExtService.refund(userInfo, dto);
                        break;
                    case NATIVE:
                        if(payOrder.getPayType()== PayMethodEnum.WALLET_PAY){
                            BigDecimal lastAmount = payOrder.getRefundAmount();
                            if(NumberUtil.isGreater(payOrder.getBalanceAmount(),BigDecimal.ZERO)){
                                if(NumberUtil.isGreaterOrEqual(payOrder.getBalanceAmount(),lastAmount)){
                                    userWalletService.addIncome(userInfo.getId(),payOrder.getRefundTradeNo(),lastAmount,BigDecimal.ZERO, WalletDetailTypeEnum.REFUND,ExpenditureRecordTypeEnum.REFUND);
                                    lastAmount = BigDecimal.ZERO;
                                }else{
                                    userWalletService.addIncome(userInfo.getId(),payOrder.getRefundTradeNo(),payOrder.getBalanceAmount(),BigDecimal.ZERO, WalletDetailTypeEnum.REFUND,ExpenditureRecordTypeEnum.REFUND);
                                    lastAmount = lastAmount.subtract(payOrder.getBalanceAmount());
                                }
                            }
                            if(NumberUtil.isGreater(payOrder.getPayBalanceAmount(),BigDecimal.ZERO)){
                                    if(NumberUtil.isGreater(lastAmount,BigDecimal.ZERO)){
                                        if(NumberUtil.isGreaterOrEqual(payOrder.getPayBalanceAmount(),lastAmount)){
                                            userWalletService.addPayBalanceIncome(userInfo.getId(),payOrder.getRefundTradeNo(),lastAmount,BigDecimal.ZERO, WalletDetailTypeEnum.REFUND,ExpenditureRecordTypeEnum.REFUND,null);
                                            lastAmount= BigDecimal.ZERO;

                                        }else{
                                            throw new GlobalRunTimeException("可退款金额不足");
                                        }
                                    }
                            }
                        }
                        break;
                }
                wantBuy.setStatus(WantBuyOrderStatusEnum.REFUND);
                wantBuy.setRefundAmount(wantBuy.getSurplusPrice());
                wantBuy.setSurplusPrice(wantBuy.getSurplusPrice().subtract(wantBuy.getRefundAmount()));
                wantBuy.updateById();
                break;
            default:
                throw new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR);
        }

    }

    @Override
    public Page myWantBuyPage(UserInfo userInfo,Page page) {
        return scrollWantBuyDao.myPage(userInfo.getId(),page);
    }

    @Override
    public Page<WantBuyDTO> wantBuyPage(Long userId,Long shopId, boolean inDao, Page page) {
        return scrollWantBuyDao.wantBuyPage(userId, shopId, inDao, page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void userSellToShop(Long id, Integer count, UserInfo userInfo, String dealPassword) {
        ScrollWantBuy wantBuy = scrollWantBuyDao.getById(id);
        Assert.notNull(wantBuy,()-> new GlobalRunTimeException("求购单不存在"));
        Assert.isTrue(wantBuy.getStatus()==WantBuyOrderStatusEnum.IN_BUY,()-> new GlobalRunTimeException("求购单状态不正确"));
        ScrollShop scrollShop = scrollShopDao.getByUserId(wantBuy.getShopUserId());
        Assert.notNull(scrollShop,()->new GlobalRunTimeException("未找到店铺"));
        Assert.isTrue(scrollShop.getStatus(),()->new GlobalRunTimeException("店铺已关闭"));
        Assert.isFalse(scrollShop.getFreezeStatus(),()->new GlobalRunTimeException("该店铺已冻结"));
        Assert.isFalse(wantBuy.getShopUserId().longValue()==userInfo.getId(),()-> new GlobalRunTimeException("无法出售给自己的店铺"));

        StaticData scrollPropsId = staticDataDao.getByType("scroll_props_id");
        Long equityId = Long.parseLong(scrollPropsId.getValue());
        if(count>(wantBuy.getWantBuyCount()- wantBuy.getBuyCount())){
            throw new GlobalRunTimeException("求购数量不足");
        }
        Assert.isFalse(wantBuy.getShopUserId().longValue()==userInfo.getId(),()-> new GlobalRunTimeException("不能向自己店铺售卖"));
        Assert.isTrue(StrUtil.equals(dealPassword,userInfo.getTransactionPassword()),()-> new GlobalRunTimeException(ErrorCode.PASSWORD_ERROR));
        List<UserEquityProps> userEquityPropsList = userEquityPropsDao.getListByUserIdAndEquityId(equityId, userInfo.getId(), count);
        if(CollUtil.isEmpty(userEquityPropsList)||userEquityPropsList.size()<count){
            throw new GlobalRunTimeException("可用道具数量不足");
        }
        BigDecimal feeAmount  ;
        ScrollConfig config = scrollConfigDao.getConfig();
        boolean inDao = userRelevanceDao.getIsExistByUserIdAndRelevanceId(wantBuy.getShopUserId(),userInfo.getId());
        if(!inDao){
            feeAmount = NumberUtil.max(config.getOutDaoAmount(),wantBuy.getUnitPrice().multiply(config.getOutDaoRatio()));
        }else{
            feeAmount = NumberUtil.max(config.getInDaoAmount(),wantBuy.getUnitPrice().multiply(config.getInDaoFee()));
        }
        //TODO 查询支付单填充收款方式6.3.6-pay
        PayOrder wantPayOrder = payOrderDao.getByOrderNo(wantBuy.getOrderNo());
        PayMethodEnum receiveType;
        if (wantPayOrder.getPayType().equals(PayMethodEnum.FAST_PAY) || wantPayOrder.getPayType().equals(PayMethodEnum.SAND_BALANCE_PAY)) {
            receiveType = PayMethodEnum.SAND_BALANCE_PAY;
        } else if (wantPayOrder.getPayType().equals(PayMethodEnum.LL_PAY) || wantPayOrder.getPayType().equals(PayMethodEnum.LL_BALANCE_PAY)) {
            receiveType = PayMethodEnum.LL_BALANCE_PAY;
        } else {
            receiveType = PayMethodEnum.WALLET_PAY;
        }
        DateTime now =DateTime.now();
        List<SecondEquityPropsOrder> secondEquityPropsOrders = Lists.newArrayList();
        BigDecimal sumAmount = BigDecimal.ZERO;
        for (UserEquityProps userEquityProps : userEquityPropsList) {
            SecondEquityPropsOrder order = new SecondEquityPropsOrder();
            order.setSecondEquityPropsId(0L);
            order.setEquityPropsId(equityId);
            order.setUserEquityPropsId(userEquityProps.getId());
            order.setSalesUserId(userInfo.getId());
            order.setBuyUserId(wantBuy.getShopUserId());
            order.setBuyPrice(wantBuy.getUnitPrice());
            order.setCharge(feeAmount);
            order.setStatus(OrderStatusEnum.PAYMENT);
            order.setOrderNo(OrderNoUtil.getOrderNo(String.valueOf(PayTypeEnum.SECOND_EQUITY_PROPS.getCode())));
            order.setDealTime(now);
            order.setCloseTime(DateUtil.offsetMinute(order.getDealTime(), 3));
            order.setPayTime(order.getDealTime());
            order.setRealAmount(order.getBuyPrice().subtract(order.getCharge()));
            order.setFirstTitle(userEquityProps.getFirstTitle());
            order.setBuySumCount(1);
            order.setIsSettlePay(false);
            order.setWantBuyOrderId(wantBuy.getId());
            order.setShopId(wantBuy.getShopId());
            //TODO 填充收款方式6.3.6-pay 根据求购单支付方式
            order.setReceiveType(receiveType);
            order.insert();
            sumAmount = sumAmount.add(order.getBuyPrice());
            secondEquityPropsOrders.add(order);
            userEquityProps.setHoldingStatus(UserEquityPropsHoldingStatusEnum.SALES);
            userEquityProps.setSecondOrderId(order.getId());
            userEquityProps.setToUserId(wantBuy.getShopUserId());
            userEquityProps.setTransferTime(order.getDealTime());
            userEquityProps.updateById();

        }
        scrollShopDao.addDealCount(scrollShop.getId(), count);

        PayOrder payOrder = new PayOrder();
        payOrder.setPayType(PayMethodEnum.WALLET_PAY);
        payOrder.setReqTime(now);
        payOrder.setUserCardId(null);
        payOrder.setCloseTime(DateUtil.offsetMinute(now, 3));
        payOrder.setOrderNo(secondEquityPropsOrders.get(0).getOrderNo());
        payOrder.setReqIp("127.0.0.1");
        payOrder.setUserId(userInfo.getId());
        payOrder.setOrderType(PayTypeEnum.SECOND_EQUITY_PROPS);
        payOrder.setPayAmount(sumAmount);
        payOrder.setRefundAmount(BigDecimal.ZERO);
        payOrder.setChannel(PayChannelEnum.NATIVE);
        payOrder.setStatus(PayStatusEnum.SUCCESS);
        payOrder.setTradeNo(UUID.fastUUID().toString().replaceAll("-", ""));
        payOrder.setUserId(wantBuy.getShopUserId());
        payOrder.insert();
        EquityProps equityProps = equityPropsDao.getById(equityId);
        userEquityPropsService.buyEquityPropsByUser(equityProps, wantBuy.getShopUserId(), UserEquityPropsGetTypeEnum.BUY, userEquityPropsList, "购买" + userEquityPropsList.get(0).getFirstTitle() + userEquityPropsList.size() + "个",
                payOrder.getId(), wantBuy.getUnitPrice());
        equityPropsDao.updateNewDealPrice(equityProps.getId(), wantBuy.getUnitPrice());
        for (SecondEquityPropsOrder secondOrder : secondEquityPropsOrders) {
            PayOrderItem payOrderItem = new PayOrderItem();
            payOrderItem.setPayOrderId(payOrder.getId());
            payOrderItem.setOrderId(secondOrder.getId());
            payOrderItem.setOrderType(SecondPayOrderItemTypeEnum.EQUITY_PROPS);
            payOrderItem.setAmount(secondOrder.getBuyPrice());
            payOrderItem.insert();
        }
        wantBuy.setBuyCount(wantBuy.getBuyCount()+count);
        wantBuy.setCostPrice(wantBuy.getCostPrice().add(sumAmount));
        wantBuy.setSurplusPrice(wantBuy.getSumPrice().subtract(sumAmount));
        if(wantBuy.getWantBuyCount().intValue()==wantBuy.getBuyCount().intValue()){
            wantBuy.setStatus(WantBuyOrderStatusEnum.FINISH);
        }
        wantBuy.updateById();

        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                SaasTaskBurialPointDTO saasTaskBurialPointDTO = new SaasTaskBurialPointDTO();
                messageQueueHelper.sendMessage(MessageTopic.DISK_TAKER, saasTaskBurialPointDTO.wallet( secondEquityPropsOrders.get(0).getBuyUserId(), SaasTaskTypeEnum.NEW_USERS_MAKE_THEIR_FIRST_PURCHASE, Convert.toBigDecimal(1), 0, equityProps.getId()),SaasTaskTypeEnum.NEW_USERS_MAKE_THEIR_FIRST_PURCHASE.name());
            }
        });
    }
}